package com.example.demo.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
public class LogAspect {

  private final Logger logger = LoggerFactory.getLogger(LogAspect.class);
  private final ObjectMapper objectMapper = new ObjectMapper();

  public LogAspect() {
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  }

  // 定义切点
  @Pointcut("execution(* com.example.demo.service..*.*(..))")
  public void serviceLog() {
  }

  @Pointcut("execution(* com.example.demo.controller..*.*(..))")
  public void controllerLog() {
  }

  // 在方法执行前打印入参
  @Before("serviceLog() || controllerLog()")
  public void doBefore(JoinPoint joinPoint) {
    try {
      // 获取请求信息
      ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      if (attributes != null) {
        HttpServletRequest request = attributes.getRequest();
        logger.info("URL: {}", request.getRequestURL().toString());
        logger.info("HTTP Method: {}", request.getMethod());
        logger.info("IP: {}", request.getRemoteAddr());
      }

      // 打印类名和方法名
      logger.info("Class Method: {}.{}",
          joinPoint.getSignature().getDeclaringTypeName(),
          joinPoint.getSignature().getName());

      // 打印请求参数
      logger.info("Request Args: {}",
          objectMapper.writeValueAsString(Arrays.asList(joinPoint.getArgs())));
    } catch (Exception e) {
      logger.error("Error logging before method execution", e);
    }
  }

  // 环绕通知，打印执行时间和返回值
  @Around("serviceLog() || controllerLog()")
  public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    long startTime = System.currentTimeMillis();

    Object result = proceedingJoinPoint.proceed();

    // 打印出参
    try {
      logger.info("Response Args: {}",
          result != null ? objectMapper.writeValueAsString(result) : null);
    } catch (Exception e) {
      logger.error("Error logging response", e);
    }

    // 打印执行时间
    long endTime = System.currentTimeMillis();
    logger.info("Time-Consuming: {} ms", (endTime - startTime));

    return result;
  }

  // 异常通知
  @AfterThrowing(pointcut = "serviceLog() || controllerLog()", throwing = "e")
  public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
    logger.error("Method {} threw exception: {}",
        joinPoint.getSignature().getName(),
        e.getMessage());
  }
} 